package com.exer1.util;

import com.exer1.Component;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfo;
import io.github.classgraph.ClassInfoList;
import io.github.classgraph.ScanResult;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

/**
 * @ClassName ContainerFactoryUtil
 * @Description 容器工厂
 * @Author Kx
 * @Date 2025/4/15 19:37
 * @Version 1.0
 */
public class ContainerFactoryUtil {

    /***
     * @author: kx
     * @date: 2025/4/15 19:40
     * @param packageName : 包名
     * @param map : 存储类的集合
     * @description: 扫描指定包中带有@Component注解的类
    */
    public void ComponentScanner(String packageName,Map<String,Object> map) {
        scanPackage(packageName,map);
    }

    public void ComponentScanner(Map<String,Object> map) {
        String packageName = "com";
        scanPackage(packageName,map);
    }

   /***
    * @author: kx
    * @date: 2025/4/15 19:40
    * @param directory : 文件夹
    * @param packageName : 包名
    * @param map : 存储类的集合
    * @description: 递归获取包下所有类,判断是否有@Component注解并且存储到集合中
   */
    private void findClasses(File directory, String packageName, Map<String,Object> map) {
        // 判断文件是否存在
        if (!directory.exists()) {
            return;
        }
        // 获取文件夹下的所有文件
        for (File file : directory.listFiles()) {
            // 判断是否是文件并且是否是类文件
            if (file.isFile() && file.getName().endsWith(".class")) {
                try {
                    // 获取当前类的Class对象
                    // 把当前包名和类名拼接成完整类名
                    Class<?> clazz = Class.forName(packageName + "." + file.getName().substring(0, file.getName().length() - 6));
                    // 判断当前类是否带有@Component注解
                    if (clazz.isAnnotationPresent(Component.class)) {
                        try {
                            // 获取当前类
                            Object obj = clazz.newInstance();
                            // 获取注解值
                            String value = clazz.getAnnotation(Component.class).value();
                            // 添加到结合中
                            map.put(value,obj);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            } else if (file.isDirectory()) { // 如果是文件夹就递归调用
                // 递归调用
                findClasses(file, packageName + "." + file.getName(),map);
            }
        }
    }

    /***
     * @author: kx
     * @date: 2025/4/16 8:30
     * @param packageName : 包名
     * @param map : 存储类的集合
     * @description: 获取指定包下所有信息
    */
    private void scanPackage(String packageName,Map<String,Object> map) {
        try {
            // 扫描项目中带有@Component注解的类
            // 获取当前线程的类加载器
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

            // 将包名转换为文件路径
            String path = packageName.replace('.', '/');

            // 获取包路径下的所有文件
            Enumeration<URL> resources = classLoader.getResources(path);

            // 创建文件集合
            List<File> files = new ArrayList<>();

            // 遍历文件
            while (resources.hasMoreElements()) {
                // 获取每个文件
                URL resource = resources.nextElement();
                // 将文件添加到集合中
                // resource.getFile()):将路径转换为file文件
                files.add(new File(resource.getFile()));
            }

            // 遍历文件集合
            for (File file : files) {
                // 递归获取包下所有类,判断是否有@Component注解
                findClasses(file, packageName, map);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /***
     * @author: kx
     * @date: 2025/4/16 8:54
     * @param packageName : 包名
     * @return io.github.classgraph.ClassInfoList : 扫描到的类集合
     * @description: 根据第三方库扫描指定包下所有类
    */
    private ClassInfoList scan(String packageName) {
        // 创建ClassGraph对象
        ClassGraph graph = new ClassGraph();

        // 指定扫描的包,并返回扫描结果集
        ScanResult result = graph.acceptPackages(packageName).scan();

        // 从结果集中取出class集合并返回
        return result.getAllClasses();
    }

    /***
     * @author: kx
     * @date: 2025/4/16 14:59
     * @param packageName : 包名
     * @description: 利用第三方库扫描指定包下带有@Component注解的类
    */
    public void init(String packageName, Map<String,Object> map) {
        // 获取扫描到的类集合
        ClassInfoList classList = scan(packageName);

        // 遍历集合
        for (ClassInfo classInfo : classList) {
           // 通过类加载器获取class对象
            Class<?> clazz = classInfo.loadClass();

            // 判断类是否带有@Component注解
            if (clazz.isAnnotationPresent(Component.class)) {
                // 将带有注解的类存放到容器中
                try {
                    // 获取注解的值
                    String value = clazz.getAnnotation(Component.class).value();
                    // 获取当前类
                    Object object = clazz.getConstructor().newInstance();

                    // 存放到容器中
                    map.put(value,object);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
